package com.example.jpademo.config;

import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.stereotype.Component;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

@Slf4j
@Component
public class EntityToVoGenericConverter implements GenericConverter {

    @PostConstruct
    public void init() {
        DefaultConversionService sharedInstance = (DefaultConversionService) DefaultConversionService.getSharedInstance();
        // 加入我们的解析 FolderEntity → FolderVo
        sharedInstance.addConverter(this);
    }

    // 不必担心性能问题，底层使用了cache存储处理
    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        Set<ConvertiblePair> convertiblePairs = new HashSet<>();
        // 不必担心性能问题，底层使用了cache存储处理
        convertiblePairs.add(new ConvertiblePair(Object.class, Object.class));
//        convertiblePairs.add(new ConvertiblePair(Map.class, Object.class));
        return convertiblePairs;
    }

    @Override
    public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        try {
            if (source instanceof Map) {
                Map map = (Map) source;
                return mapToBean(map, targetType.getType());
            }

            // 直接创建结果对象
            Object instance = targetType.getType().getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(source, instance);
            return instance;
        } catch (Exception e) {
            log.error("无法解析的映射！", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * map转对象
     * @param map
     * @param beanClass
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T mapToBean(Map map, Class<T> beanClass) throws Exception {
        T object = beanClass.newInstance();
        BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor property : propertyDescriptors) {
            Method setter = property.getWriteMethod();
            if (setter != null) {
                setter.invoke(object, map.get(property.getName()));
            }
        }
        return object;
    }
}